package com.study.juc.rwlock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * @program: juc-study
 * @author: jzhou
 * @date: 2022-08-23 10:26
 * @version: 1.0
 * @description: 邮戳锁 是对reentrantReadWriteLock的优化 读的过程中也允许写锁介入
 *
 * stampedLock = ReentrantReadWriteLock + 读的过程也允许获取写锁介入
 **/
public class StampedLockDemo {

	static int number = 37;
	static StampedLock stampedLock = new StampedLock();

	/**
	 * 使用 StampedLock 模拟 ReentrantReadWriteLock 的功能
	 */
	public void write(){
		long stamp = stampedLock.writeLock();
		System.out.println(Thread.currentThread().getName() +"\t"+ "写线程准备修改");
		try {
			number = number + 13;
		}finally {
			stampedLock.unlockWrite(stamp);
		}
		System.out.println(Thread.currentThread().getName() +"\t"+ "写线程修改完成");
	}

	/**
	 * 使用 StampedLock 模拟 ReentrantReadWriteLock 的功能
	 */
	public void read(){
		long stamp = stampedLock.readLock();
		System.out.println(Thread.currentThread().getName() +"\t"+ "读线程 come in...");

		for (int i = 0; i < 5; i++) {
			try {
				TimeUnit.SECONDS.sleep(1);
				System.out.println("读线程正在读取");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		try {
			int result = number;
			System.out.println(Thread.currentThread().getName() +"\t"+ "获取结果变量 " + result);
		}finally {
			stampedLock.unlockRead(stamp);
		}
	}

	/**
	 * 乐观读，读过程中允许获取写锁，假如被修改再手动升级为悲观读模式
	 */
	public void tryOptimisticRead(){
		long stamp = stampedLock.tryOptimisticRead();
		int result = number;
//		stampedLock.validate(stamp)   返回 true 表示无修改，返回 false 表示有修改
		System.out.println("刚开始 tryOptimisticRead 时 validate 状态" + stampedLock.validate(stamp));
		for (int i = 0; i < 5; i++) {
			try {
				TimeUnit.SECONDS.sleep(1);
				System.out.println("读线程正在 "+ i +" 次读取，validate 状态" + stampedLock.validate(stamp) + "\t" + result);
//				if (!stampedLock.validate(stamp)) break;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		if(!stampedLock.validate(stamp)){
			System.out.println("有人修改过,需要从 乐观读 修改为 悲观读");
			stamp = stampedLock.readLock();
			try {
				result = number;
				System.out.println("重新悲观读锁通过获取到的成员变量值result = " + result);
			} finally {
				stampedLock.unlockRead(stamp);
			}
		}
		System.out.println(Thread.currentThread().getName()+"\t finally value: "+result);

	}

	public static void main(String[] args) {
		StampedLockDemo demo = new StampedLockDemo();
/*		使用 stampedLock 传统版读写
        new Thread(() -> {demo.read();},"readThread").start();
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		new Thread(() -> {demo.write();},"writeThread").start();

		try {
			TimeUnit.SECONDS.sleep(5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}*/


		new Thread(() -> {demo.tryOptimisticRead();},"readThread").start();
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		new Thread(() -> {demo.write();},"writeThread").start();



//		System.out.println(Thread.currentThread().getName() +"\t"+ number);
	}
}
